using OpenCvSharp;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Xml.Linq;
using Point = System.Windows.Point;
using Rect = System.Windows.Rect;

namespace OverSizeImage
{


    /// <summary>
    /// ImageShowControl.xaml 的交互逻辑
    /// </summary>
    public partial class ImageShowControl : UserControl
    {
        #region 依赖属性

        /// <summary>
        /// 是否显示全部框
        /// </summary>
        public bool ShowAllElement
        {
            get { return (bool)GetValue(ShowAllElementProperty); }
            set { SetValue(ShowAllElementProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ShowAllElement.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ShowAllElementProperty =
            DependencyProperty.Register("ShowAllElement", typeof(bool), typeof(ImageShowControl), new PropertyMetadata(true));


        /// <summary>
        /// 坐标信息是否显示
        /// </summary>
        public Visibility PositionVisit
        {
            get { return (Visibility)GetValue(PositionVisitProperty); }
            set { SetValue(PositionVisitProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PositionVisit.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PositionVisitProperty =
            DependencyProperty.Register("PositionVisit", typeof(Visibility), typeof(ImageShowControl), new PropertyMetadata(Visibility.Visible));


        /// <summary>
        /// 图像缩放比例
        /// </summary>
        public double ImageScale
        {
            get { return (double)GetValue(ImageScaleProperty); }
            set { SetValue(ImageScaleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ImageScale.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ImageScaleProperty =
            DependencyProperty.Register("ImageScale", typeof(double), typeof(ImageShowControl), new PropertyMetadata(1.0, (sender, e) =>
            {
                var dp = sender as ImageShowControl;
                if (dp == null) return;
                dp.ImageScaleChanged();
            }));


        /// <summary>
        /// 动画使能
        /// </summary>
        public bool AnimationEnabled
        {
            get { return (bool)GetValue(AnimationEnabledProperty); }
            set { SetValue(AnimationEnabledProperty, value); }
        }

        // Using a DependencyProperty as the backing store for AnimationEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AnimationEnabledProperty =
            DependencyProperty.Register("AnimationEnabled", typeof(bool), typeof(ImageShowControl), new PropertyMetadata(true));



        /// <summary>
        /// 鼠标滚轮缩放使能
        /// </summary>
        public bool MouseWheelEnabled
        {
            get { return (bool)GetValue(MouseWheelEnabledProperty); }
            set { SetValue(MouseWheelEnabledProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MouseWheelEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MouseWheelEnabledProperty =
            DependencyProperty.Register("MouseWheelEnabled", typeof(bool), typeof(ImageShowControl), new PropertyMetadata(true));



        public double ManualScale
        {
            get { return (double)GetValue(ManualScaleProperty); }
            set { SetValue(ManualScaleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ManualScale.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ManualScaleProperty =
            DependencyProperty.Register("ManualScale", typeof(double), typeof(ImageShowControl), new PropertyMetadata(1.0, (sender, e) =>
            {
                var dp = sender as ImageShowControl;
                if (dp == null) return;
                dp.ManualScaleChanged();
            }));





        /// <summary>
        /// Mapping启用使能
        /// </summary>
        public bool MappingEnabled
        {
            get { return (bool)GetValue(MappingEnabledProperty); }
            set { SetValue(MappingEnabledProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MappingEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MappingEnabledProperty =
            DependencyProperty.Register("MappingEnabled", typeof(bool), typeof(ImageShowControl), new PropertyMetadata(false));


        /// <summary>
        /// 限制最小缩放
        /// </summary>
        public bool LitmitScaleMin
        {
            get { return (bool)GetValue(LitmitScaleMinProperty); }
            set { SetValue(LitmitScaleMinProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LitmitScaleMin.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LitmitScaleMinProperty =
            DependencyProperty.Register("LitmitScaleMin", typeof(bool), typeof(ImageShowControl), new PropertyMetadata(false));



        /// <summary>
        /// Mapping是否显示
        /// </summary>
        public Visibility MappingVisit
        {
            get { return (Visibility)GetValue(MappingVisitProperty); }
            set { SetValue(MappingVisitProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MappingVisit.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MappingVisitProperty =
            DependencyProperty.Register("MappingVisit", typeof(Visibility), typeof(ImageShowControl), new PropertyMetadata(Visibility.Collapsed));



        public BitmapImage MappingSource
        {
            get { return (BitmapImage)GetValue(MappingSourceProperty); }
            set { SetValue(MappingSourceProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MappingSource.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MappingSourceProperty =
            DependencyProperty.Register("MappingSource", typeof(BitmapImage), typeof(ImageShowControl), new PropertyMetadata(null));



        public double MappingWidth
        {
            get { return (double)GetValue(MappingWidthProperty); }
            set { SetValue(MappingWidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MappingWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MappingWidthProperty =
            DependencyProperty.Register("MappingWidth", typeof(double), typeof(ImageShowControl), new PropertyMetadata(100.0));




        public double MappingHeight
        {
            get { return (double)GetValue(MappingHeightProperty); }
            set { SetValue(MappingHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MappingHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MappingHeightProperty =
            DependencyProperty.Register("MappingHeight", typeof(double), typeof(ImageShowControl), new PropertyMetadata(100.0));



        /// <summary>
        /// 是否独立STA
        /// </summary>
        public bool IsSTA
        {
            get { return (bool)GetValue(IsSTAProperty); }
            set { SetValue(IsSTAProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsSTA.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsSTAProperty =
            DependencyProperty.Register("IsSTA", typeof(bool), typeof(ImageShowControl), new PropertyMetadata(false));



        /// <summary>
        /// 是否缓存上一组图片(瓦片模式下)
        /// </summary>
        public bool CacheLastImage
        {
            get { return (bool)GetValue(CacheLastImageProperty); }
            set { SetValue(CacheLastImageProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CacheLastImage.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CacheLastImageProperty =
            DependencyProperty.Register("CacheLastImage", typeof(bool), typeof(ImageShowControl), new PropertyMetadata(false));


        /// <summary>
        /// 图片控件集合(除独立STA模式&位图模式)
        /// </summary>
        public ObservableCollection<Image> ImageList
        {
            get { return (ObservableCollection<Image>)GetValue(ImageListProperty); }
            set { SetValue(ImageListProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ImageList.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ImageListProperty =
            DependencyProperty.Register("ImageList", typeof(ObservableCollection<Image>), typeof(ImageShowControl), new PropertyMetadata(null));


        /// <summary>
        /// 图片源
        /// </summary>
        public BitmapImage ImageSource
        {
            get { return (BitmapImage)GetValue(ImageSourceProperty); }
            set { SetValue(ImageSourceProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ImageSource.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ImageSourceProperty =
            DependencyProperty.Register("ImageSource", typeof(BitmapImage), typeof(ImageShowControl), new PropertyMetadata(null));


        /// <summary>
        /// 示意图图片源
        /// </summary>
        public BitmapImage SketchImageSource
        {
            get { return (BitmapImage)GetValue(SketchImageSourceProperty); }
            set { SetValue(SketchImageSourceProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SketchImageSource.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SketchImageSourceProperty =
            DependencyProperty.Register("SketchImageSource", typeof(BitmapImage), typeof(ImageShowControl), new PropertyMetadata(null));


        /// <summary>
        /// 图片数据byte数组
        /// </summary>
        public byte[] ImageData
        {
            get { return (byte[])GetValue(ImageDataProperty); }
            set { SetValue(ImageDataProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ImageData.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ImageDataProperty =
            DependencyProperty.Register("ImageData", typeof(byte[]), typeof(ImageShowControl), new PropertyMetadata(null, (sender, e) =>
            {
                var dp = sender as ImageShowControl;
                if (dp == null) return;
                dp.ImageRefush();

            }));


        /// <summary>
        /// 示意图数据byte数组
        /// </summary>
        public byte[] SketchByte
        {
            get { return (byte[])GetValue(SketchByteProperty); }
            set { SetValue(SketchByteProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SketchByte.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SketchByteProperty =
            DependencyProperty.Register("SketchByte", typeof(byte[]), typeof(ImageShowControl), new PropertyMetadata(null, (sender, e) =>
            {
                var dp = sender as ImageShowControl;
                if (dp == null) return;
                dp.SketchImageRefush();
            }));


        /// <summary>
        /// 处理提示是否显示(仅瓦片模式)
        /// </summary>
        public Visibility HandTipVisit
        {
            get { return (Visibility)GetValue(HandTipVisitProperty); }
            set { SetValue(HandTipVisitProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HandTipVisit.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HandTipVisitProperty =
            DependencyProperty.Register("HandTipVisit", typeof(Visibility), typeof(ImageShowControl), new PropertyMetadata(Visibility.Collapsed));



        /// <summary>
        /// 处理提示字符串(仅瓦片模式)
        /// </summary>
        public string HandTip
        {
            get { return (string)GetValue(HandTipProperty); }
            set { SetValue(HandTipProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HandTip.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HandTipProperty =
            DependencyProperty.Register("HandTip", typeof(string), typeof(ImageShowControl), new PropertyMetadata(string.Empty));


        /// <summary>
        /// 当前鼠标基于原图像素坐标X
        /// </summary>
        public double Position_X
        {
            get { return (double)GetValue(Position_XProperty); }
            set { SetValue(Position_XProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Position_X.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty Position_XProperty =
            DependencyProperty.Register("Position_X", typeof(double), typeof(ImageShowControl), new PropertyMetadata(0.0));


        /// <summary>
        /// 当前鼠标基于原图像素坐标Y
        /// </summary>
        public double Position_Y
        {
            get { return (double)GetValue(Position_YProperty); }
            set { SetValue(Position_YProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Position_Y.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty Position_YProperty =
            DependencyProperty.Register("Position_Y", typeof(double), typeof(ImageShowControl), new PropertyMetadata(0.0));



        public Visibility ElementNameVisit
        {
            get { return (Visibility)GetValue(ElementNameVisitProperty); }
            set { SetValue(ElementNameVisitProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ElementNameVisit.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ElementNameVisitProperty =
            DependencyProperty.Register("ElementNameVisit", typeof(Visibility), typeof(ImageShowControl), new PropertyMetadata(Visibility.Collapsed));




        /// <summary>
        /// 图片路径
        /// </summary>
        public string ImagePath
        {
            get { return (string)GetValue(ImagePathProperty); }
            set { SetValue(ImagePathProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ImagePath.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ImagePathProperty =
            DependencyProperty.Register("ImagePath", typeof(string), typeof(ImageShowControl), new UIPropertyMetadata(string.Empty, (sender, e) =>
            {
                var dp = sender as ImageShowControl;
                if (dp == null) return;
                dp.GetImagePath();
            }));


        /// <summary>
        /// 图片加载模式
        /// </summary>
        public ImageLoadModelEnum LoadModel
        {
            get { return (ImageLoadModelEnum)GetValue(LoadModelProperty); }
            set { SetValue(LoadModelProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LoadModel.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LoadModelProperty =
            DependencyProperty.Register("LoadModel", typeof(ImageLoadModelEnum), typeof(ImageShowControl), new PropertyMetadata(ImageLoadModelEnum.正常));



        /// <summary>
        /// 控件状态 概览-正常查看图片 浏览-允许拖动缩放 编辑-允许编辑框
        /// </summary>
        public ImageStatusEnum Status
        {
            get { return (ImageStatusEnum)GetValue(StatusProperty); }
            set { SetValue(StatusProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Status.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StatusProperty =
            DependencyProperty.Register("Status", typeof(ImageStatusEnum), typeof(ImageShowControl), new PropertyMetadata(ImageStatusEnum.概览, (sender, e) =>
            {
                var dp = sender as ImageShowControl;
                if (dp == null) return;
                dp.StatusChanged();
            }));



        /// <summary>
        /// 基于画布X
        /// </summary>
        public double CanvasX
        {
            get { return (double)GetValue(CanvasXProperty); }
            set { SetValue(CanvasXProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CanvasX.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CanvasXProperty =
            DependencyProperty.Register("CanvasX", typeof(double), typeof(ImageShowControl), new PropertyMetadata(0.0));

        /// <summary>
        /// 基于画布Y
        /// </summary>
        public double CanvasY
        {
            get { return (double)GetValue(CanvasYProperty); }
            set { SetValue(CanvasYProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CanvasY.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CanvasYProperty =
            DependencyProperty.Register("CanvasY", typeof(double), typeof(ImageShowControl), new PropertyMetadata(0.0));

        /// <summary>
        /// 整体X缩放
        /// </summary>
        public double ScaleX
        {
            get { return (double)GetValue(ScaleXProperty); }
            set { SetValue(ScaleXProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScaleX.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScaleXProperty =
            DependencyProperty.Register("ScaleX", typeof(double), typeof(ImageShowControl), new PropertyMetadata(1.0));



        /// <summary>
        /// 整体Y缩放
        /// </summary>
        public double ScaleY
        {
            get { return (double)GetValue(ScaleYProperty); }
            set { SetValue(ScaleYProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScaleY.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScaleYProperty =
            DependencyProperty.Register("ScaleY", typeof(double), typeof(ImageShowControl), new PropertyMetadata(1.0));


        /// <summary>
        /// 最小缩放比例
        /// </summary>
        public double ScaleMin
        {
            get { return (double)GetValue(ScaleMinProperty); }
            set { SetValue(ScaleMinProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScaleMin.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScaleMinProperty =
            DependencyProperty.Register("ScaleMin", typeof(double), typeof(ImageShowControl), new PropertyMetadata(0.01));


        /// <summary>
        /// 最大缩放比例
        /// </summary>
        public double ScaleMax
        {
            get { return (double)GetValue(ScaleMaxProperty); }
            set { SetValue(ScaleMaxProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScaleMax.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScaleMaxProperty =
            DependencyProperty.Register("ScaleMax", typeof(double), typeof(ImageShowControl), new PropertyMetadata(10.0));



        /// <summary>
        /// 像素毫米比
        /// </summary>
        public double PxToMM
        {
            get { return (double)GetValue(PxToMMProperty); }
            set { SetValue(PxToMMProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PxToMM.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PxToMMProperty =
            DependencyProperty.Register("PxToMM", typeof(double), typeof(ImageShowControl), new PropertyMetadata(0.016));


        /// <summary>
        /// 标尺是否显示
        /// </summary>
        public Visibility RulerVisit
        {
            get { return (Visibility)GetValue(RulerVisitProperty); }
            set { SetValue(RulerVisitProperty, value); }
        }

        // Using a DependencyProperty as the backing store for RulerVisit.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RulerVisitProperty =
            DependencyProperty.Register("RulerVisit", typeof(Visibility), typeof(ImageShowControl), new PropertyMetadata(Visibility.Visible));



        public Brush RulerColor
        {
            get { return (Brush)GetValue(RulerColorProperty); }
            set { SetValue(RulerColorProperty, value); }
        }

        // Using a DependencyProperty as the backing store for RulerColor.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RulerColorProperty =
            DependencyProperty.Register("RulerColor", typeof(Brush), typeof(ImageShowControl), new PropertyMetadata(Brushes.White));



        /// <summary>
        /// 旋转角度
        /// </summary>
        public double Angle
        {
            get { return (double)GetValue(AngleProperty); }
            set { SetValue(AngleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Angle.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AngleProperty =
            DependencyProperty.Register("Angle", typeof(double), typeof(ImageShowControl), new PropertyMetadata(0.0));

        /// <summary>
        /// 图像填充方式
        /// </summary>
        public Stretch Stretch
        {
            get { return (Stretch)GetValue(StretchProperty); }
            set { SetValue(StretchProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Stretch.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StretchProperty =
            DependencyProperty.Register("Stretch", typeof(Stretch), typeof(ImageShowControl), new PropertyMetadata(Stretch.Uniform));

        /// <summary>
        /// 框元素集合
        /// </summary>
        public ObservableCollection<ElementBaseModel> ElementList
        {
            get { return (ObservableCollection<ElementBaseModel>)GetValue(ElementListProperty); }
            set { SetValue(ElementListProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ElementList.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ElementListProperty =
            DependencyProperty.Register("ElementList", typeof(ObservableCollection<ElementBaseModel>), typeof(ImageShowControl), new PropertyMetadata(null, (sender, e) =>
            {
                var dp = sender as ImageShowControl;
                if (dp == null) return;
                dp.ElementRefush();
            }));

        /// <summary>
        /// 框控件集合
        /// </summary>
        public ObservableCollection<ElementControl> ControlList
        {
            get { return (ObservableCollection<ElementControl>)GetValue(ControlListProperty); }
            set { SetValue(ControlListProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ControlList.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ControlListProperty =
            DependencyProperty.Register("ControlList", typeof(ObservableCollection<ElementControl>), typeof(ImageShowControl), new PropertyMetadata(null));


        /// <summary>
        /// 脏区X(仅位图模式)
        /// </summary>
        public int Dirty_X
        {
            get { return (int)GetValue(Dirty_XProperty); }
            set { SetValue(Dirty_XProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Dirty_X.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty Dirty_XProperty =
            DependencyProperty.Register("Dirty_X", typeof(int), typeof(ImageShowControl), new PropertyMetadata(-1));


        /// <summary>
        /// 脏区Y(仅位图模式)
        /// </summary>
        public int Dirty_Y
        {
            get { return (int)GetValue(Dirty_YProperty); }
            set { SetValue(Dirty_YProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Dirty_Y.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty Dirty_YProperty =
            DependencyProperty.Register("Dirty_Y", typeof(int), typeof(ImageShowControl), new PropertyMetadata(-1));


        /// <summary>
        /// 脏区Width(仅位图模式)
        /// </summary>
        public int Dirty_Width
        {
            get { return (int)GetValue(Dirty_WidthProperty); }
            set { SetValue(Dirty_WidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Dirty_Width.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty Dirty_WidthProperty =
            DependencyProperty.Register("Dirty_Width", typeof(int), typeof(ImageShowControl), new PropertyMetadata(-1));

        /// <summary>
        /// 脏区Height(仅位图模式)
        /// </summary>
        public int Dirty_Height
        {
            get { return (int)GetValue(Dirty_HeightProperty); }
            set { SetValue(Dirty_HeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Dirty_Height.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty Dirty_HeightProperty =
            DependencyProperty.Register("Dirty_Height", typeof(int), typeof(ImageShowControl), new PropertyMetadata(-1));




        /// <summary>
        /// 像素编码使能
        /// </summary>
        public bool DecodePixelEnabled
        {
            get { return (bool)GetValue(DecodePixelEnabledProperty); }
            set { SetValue(DecodePixelEnabledProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DecodePixelEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DecodePixelEnabledProperty =
            DependencyProperty.Register("DecodePixelEnabled", typeof(bool), typeof(ImageShowControl), new PropertyMetadata(false));


        /// <summary>
        /// 是否自动切换像素解析度(仅正常加载模式，性能较差但显示效果最优)
        /// </summary>
        public bool AutoDecodePixelEnabled
        {
            get { return (bool)GetValue(AutoDecodePixelEnabledProperty); }
            set { SetValue(AutoDecodePixelEnabledProperty, value); }
        }

        // Using a DependencyProperty as the backing store for AutoDecodePixelEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AutoDecodePixelEnabledProperty =
            DependencyProperty.Register("AutoDecodePixelEnabled", typeof(bool), typeof(ImageShowControl), new PropertyMetadata(false));



        /// <summary>
        /// 像素编码分辨率
        /// </summary>
        public int DecodePixelValue
        {
            get { return (int)GetValue(DecodePixelValueProperty); }
            set { SetValue(DecodePixelValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DecodePixelValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DecodePixelValueProperty =
            DependencyProperty.Register("DecodePixelValue", typeof(int), typeof(ImageShowControl), new PropertyMetadata(1080, (sender, e) =>
            {
                var dp = sender as ImageShowControl;
                if (dp == null) return;
                dp.ImageRefush();
            }));

        /// <summary>
        /// 聚焦框
        /// </summary>
        public ElementBaseModel FocusRect
        {
            get { return (ElementBaseModel)GetValue(FocusRectProperty); }
            set { SetValue(FocusRectProperty, value); }
        }

        // Using a DependencyProperty as the backing store for FocusRect.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FocusRectProperty =
            DependencyProperty.Register("FocusRect", typeof(ElementBaseModel), typeof(ImageShowControl), new PropertyMetadata(null, (sender, e) =>
            {
                var dp = sender as ImageShowControl;
                if (dp == null) return;
                dp.FocusRectChanged();
            }));

        /// <summary>
        /// 图像宽度
        /// </summary>
        public double ImageWidth
        {
            get { return (double)GetValue(ImageWidthProperty); }
            set { SetValue(ImageWidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ImageWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ImageWidthProperty =
            DependencyProperty.Register("ImageWidth", typeof(double), typeof(ImageShowControl), new PropertyMetadata(1920.0));

        /// <summary>
        /// 图像高度
        /// </summary>
        public double ImageHeight
        {
            get { return (double)GetValue(ImageHeightProperty); }
            set { SetValue(ImageHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ImageHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ImageHeightProperty =
            DependencyProperty.Register("ImageHeight", typeof(double), typeof(ImageShowControl), new PropertyMetadata(1080.0));

        /// <summary>
        /// 正在编辑的框边框颜色
        /// </summary>
        public Brush DrawingRectBrush
        {
            get { return (Brush)GetValue(DrawingRectBrushProperty); }
            set { SetValue(DrawingRectBrushProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DrawingRectBrush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DrawingRectBrushProperty =
            DependencyProperty.Register("DrawingRectBrush", typeof(Brush), typeof(ImageShowControl), new PropertyMetadata(Brushes.Green));

        /// <summary>
        /// 缩放更改像素解析度所需次数(需要AutoDecodePixelEnabled == true 或 瓦片模式)
        /// </summary>

        public int DecodeChangeByScaleCount
        {
            get { return (int)GetValue(DecodeChangeByScaleCountProperty); }
            set { SetValue(DecodeChangeByScaleCountProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DecodeChangeByScaleCount.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DecodeChangeByScaleCountProperty =
            DependencyProperty.Register("DecodeChangeByScaleCount", typeof(int), typeof(ImageShowControl), new PropertyMetadata(3));


        /// <summary>
        /// 选中几何形状，决定当前编辑的几何框
        /// </summary>
        public ShapeEnum SelectedShape
        {
            get { return (ShapeEnum)GetValue(SelectedShapeProperty); }
            set { SetValue(SelectedShapeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SelectedShape.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SelectedShapeProperty =
            DependencyProperty.Register("SelectedShape", typeof(ShapeEnum), typeof(ImageShowControl), new PropertyMetadata(ShapeEnum.矩形));


        /// <summary>
        /// 移动是否能超出图像边界
        /// </summary>
        public bool MoveOverEnabled
        {
            get { return (bool)GetValue(MoveOverEnabledProperty); }
            set { SetValue(MoveOverEnabledProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MoveOverEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MoveOverEnabledProperty =
            DependencyProperty.Register("MoveOverEnabled", typeof(bool), typeof(ImageShowControl), new PropertyMetadata(true));

        /// <summary>
        /// 画布移动X(px)
        /// </summary>
        public double MouseX
        {
            get { return (double)GetValue(MouseXProperty); }
            set { SetValue(MouseXProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MouseX.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MouseXProperty =
            DependencyProperty.Register("MouseX", typeof(double), typeof(ImageShowControl), new PropertyMetadata(0.0));

        /// <summary>
        /// 画布移动Y(px)
        /// </summary>
        public double MouseY
        {
            get { return (double)GetValue(MouseYProperty); }
            set { SetValue(MouseYProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MouseY.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MouseYProperty =
            DependencyProperty.Register("MouseY", typeof(double), typeof(ImageShowControl), new PropertyMetadata(0.0));


        /// <summary>
        /// 瓦片行数(仅瓦片加载模式)
        /// </summary>
        public int TileRows
        {
            get { return (int)GetValue(TileRowsProperty); }
            set { SetValue(TileRowsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TileRows.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TileRowsProperty =
            DependencyProperty.Register("TileRows", typeof(int), typeof(ImageShowControl), new PropertyMetadata(3));



        /// <summary>
        /// 瓦片列数(仅瓦片加载模式)
        /// </summary>
        public int TileColumns
        {
            get { return (int)GetValue(TileColumnsProperty); }
            set { SetValue(TileColumnsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TileColumns.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TileColumnsProperty =
            DependencyProperty.Register("TileColumns", typeof(int), typeof(ImageShowControl), new PropertyMetadata(3));

        #endregion

        #region 命令

        #endregion

        #region 字段
        /// <summary>
        /// 待刷新的瓦片数据
        /// </summary>
        ConcurrentQueue<BackWorkTileModel> tileQueue = new ConcurrentQueue<BackWorkTileModel>();
        /// <summary>
        /// 后台存储图片路径
        /// </summary>
        private string back_ImagePath = string.Empty;
        /// <summary>
        /// 后台存储瓦片列数
        /// </summary>
        private int back_TileColumns = 9;
        /// <summary>
        /// 后台存储瓦片行数
        /// </summary>
        private int back_TileRows = 9;
        /// <summary>
        /// 后台存储图片宽度
        /// </summary>
        private int back_ImageWidth = 0;
        /// <summary>
        /// 后台存储图片高度
        /// </summary>
        private int back_ImageHeight = 0;
        /// <summary>
        /// 后台存储脏区X
        /// </summary>
        private int back_Dirty_X = -1;
        /// <summary>
        /// 后台存储脏区Y
        /// </summary>
        private int back_Dirty_Y = -1;
        /// <summary>
        /// 后台存储脏区宽
        /// </summary>
        private int back_Dirty_Width = -1;
        /// <summary>
        /// 后台存储脏区高
        /// </summary>
        private int back_Dirty_Height = -1;
        /// <summary>
        /// 后台存储缓存上一组图片使能(瓦片)
        /// </summary>
        bool back_CacheLastImage = false;
        /// <summary>
        /// 图像控件Key集合
        /// </summary>
        List<string> imageKeyList = new List<string>();
        /// <summary>
        /// 快速获取的图片信息
        /// </summary>
        BitmapFrame fastFrame;
        /// <summary>
        /// 当前图片的像素格式
        /// </summary>
        System.Windows.Media.PixelFormat format;
        /// <summary>
        /// 独立STA线程状态(仅位图模式&独立STA)
        /// </summary>
        bool staStatus = false;
        /// <summary>
        /// 是否独立STA创建中
        /// </summary>
        bool staCreating = false;
        /// <summary>
        /// 缓存的瓦片原图(仅瓦片模式)
        /// </summary>
        Mat tileSrcMat = new Mat();
        /// <summary>
        /// 独立STA线程下的图像控件(仅位图模式&独立STA)
        /// </summary>
        Image staImage;
        /// <summary>
        /// 最近一次瓦片数据入队时间
        /// </summary>
        DateTime lastEnqueueTileTime = DateTime.Now;

        /// <summary>
        /// 当前需要刷新的瓦片Key
        /// </summary>
        long currentTileKey = -1;
        /// <summary>
        /// 原始X
        /// </summary>
        private double orgX = 0.0;

        /// <summary>
        /// 原始Y
        /// </summary>
        private double orgY = 0.0;

        /// <summary>
        /// 原始X缩放
        /// </summary>
        private double orgScaleX = 1.0;

        /// <summary>
        /// 原始Y缩放
        /// </summary>
        private double orgScaleY = 1.0;

        /// <summary>
        /// 左键是否按下(补充判断)
        /// </summary>
        private bool isLeftMouseDown = false;

        /// <summary>
        /// 当前正在编辑的框
        /// </summary>
        private ElementBaseModel drawingRect = null;

        /// <summary>
        /// 上次鼠标左键点击位置
        /// </summary>
        Point lastMouseLeftDownPoint;

        /// <summary>
        /// 上次鼠标左键点击位置(Mapping)
        /// </summary>
        Point lastMouseLeftDownPoint_Mapping;

        /// <summary>
        /// 鼠标滚轮倍率
        /// </summary>
        double mouseWheelstep = 1.2;

        /// <summary>
        /// 当前缩放次数
        /// </summary>
        int scaleChangeTimes = 0;

        /// <summary>
        /// 显示区域实际宽度
        /// </summary>
        double showAreaActualWidth = 0.0;

        /// <summary>
        /// 显示区域实际高度
        /// </summary>
        double showAreaActualHeight = 0.0;

        /// <summary>
        /// 不超出图像边界下的最小缩放比例(需不超出图像边界启用)
        /// </summary>
        double scaleMinByNoMoveOver = 0.0;

        /// <summary>
        /// 显示缩放比例动画故事板
        /// </summary>
        Storyboard showScaleStoryBoard;

        /// <summary>
        /// 缩放动画
        /// </summary>
        Storyboard scaleStoryBoard;

        /// <summary>
        /// 上次手动缩放系数
        /// </summary>
        double lastManualScale = 1.0;

        /// <summary>
        /// 实际计算缩放X
        /// </summary>
        double calc_ScaleX = 0.0;
        /// <summary>
        /// 实际计算缩放Y
        /// </summary>
        double calc_ScaleY = 0.0;
        /// <summary>
        /// 实际计算画布X
        /// </summary>
        double calc_CanvasX = 0.0;
        /// <summary>
        /// 实际计算画布Y
        /// </summary>
        double calc_CanvasY = 0.0;
        #endregion

        #region 公共
        /// <summary>
        /// 图片缩放比例更变处理
        /// </summary>
        private void ImageScaleChanged()
        {
            if (showScaleStoryBoard == null)
            {
                showScaleStoryBoard = new Storyboard();
                showScaleStoryBoard.Completed += ShowScaleStoryBoard_Completed;
            }
            else
            {
                showScaleStoryBoard.Stop();
                showScaleStoryBoard.Children.Clear();
            }
            Border_Scale.Visibility = Visibility.Visible;
            DoubleAnimation animation = new DoubleAnimation()
            {
                From = 1,
                To = 0,
                Duration = new Duration(new TimeSpan(0, 0, 0,0,1500)),
                AccelerationRatio = 0.8,
                FillBehavior = FillBehavior.HoldEnd,
                AutoReverse = false
            };
            Storyboard.SetTarget(animation, Border_Scale);
            Storyboard.SetTargetProperty(animation, new PropertyPath("Opacity"));
            showScaleStoryBoard.Children.Add(animation);
            showScaleStoryBoard.Begin(Border_Scale, true);
        }

        private void ShowScaleStoryBoard_Completed(object sender, EventArgs e)
        {
            Border_Scale.Visibility = Visibility.Collapsed;
        }

        /// <summary>
        /// 缩放处理
        /// </summary>
        /// <param name="mousePoint"></param>
        /// <param name="delta"></param>
        private void ScaleHand(Point mousePoint, int delta)
        {
                double sX = 1.0, sY = 1.0, cX = 0.0, cY = 0.0;
            if (delta > 0)
            {
                if (calc_ScaleX * mouseWheelstep <= ScaleMax && calc_ScaleY * mouseWheelstep <= ScaleMax)
                {
                    double px = mousePoint.X - calc_CanvasX;
                    double py = mousePoint.Y - calc_CanvasY;
                    double px_add = px * (mouseWheelstep - 1.0);
                    double py_add = py * (mouseWheelstep - 1.0);
                    sX = calc_ScaleX * mouseWheelstep;
                    sY = calc_ScaleY * mouseWheelstep;
                    cX = calc_CanvasX - px_add;
                    cY = calc_CanvasY - py_add;
                    if (AnimationEnabled)
                    {
                        if (scaleStoryBoard == null)
                        {
                            scaleStoryBoard = new Storyboard();
                            scaleStoryBoard.Completed += ScaleStoryBoard_Completed;
                        }
                        else
                        {
                            scaleStoryBoard.Stop();
                            //CanvasX = calc_CanvasX;
                            //CanvasY = calc_CanvasY;
                            ScaleX = calc_ScaleX;
                            ScaleY = calc_ScaleY;
                            scaleStoryBoard.Children.Clear();
                        }
                        calc_ScaleX = sX;
                        calc_ScaleY = sY;
                        calc_CanvasX = cX;
                        calc_CanvasY = cY;
                        List<DoubleAnimation> animations = CreateAnimationByScale();
                        foreach (var item in animations)
                        {
                            scaleStoryBoard.Children.Add(item);

                        }
                        scaleStoryBoard.Begin(this, true);
                    }
                    else
                    {
                        calc_CanvasX = CanvasX = cX;
                        calc_CanvasY = CanvasY = cY;
                        calc_ScaleX = ScaleX = sX;
                        calc_ScaleY = ScaleY = sY;
                    }
                    scaleChangeTimes++;
                    Canvas.SetLeft(Rect_Mapping, -cX / sX * MappingWidth / ImageWidth);
                    Canvas.SetTop(Rect_Mapping, -cY / sY * MappingHeight / ImageHeight);
                    Rect_Mapping.Width = MappingWidth * showAreaActualWidth / sX / ImageWidth;
                    Rect_Mapping.Height = MappingHeight * showAreaActualHeight / sY / ImageHeight;
                    if (Rect_Mapping.Width > MappingWidth || Rect_Mapping.Height > MappingHeight)
                        MappingVisit = Visibility.Collapsed;
                    else
                        MappingVisit = Visibility.Visible;

                    if (Math.Abs(scaleChangeTimes) >= DecodeChangeByScaleCount)
                    {
                        switch (LoadModel)
                        {
                            case ImageLoadModelEnum.正常:
                                if (AutoDecodePixelEnabled)
                                    ImageRefush(false);
                                break;
                            case ImageLoadModelEnum.瓦片:
                                TileRefush(new Point(showAreaActualWidth / 2, showAreaActualHeight / 2), (int)(ImageWidth * sX), true);
                                break;
                        }
                        scaleChangeTimes = 0;
                    }
                }
                else
                    return;
            }
            else
            {
                if ((MoveOverEnabled && calc_ScaleX / mouseWheelstep >= ScaleMin && calc_ScaleY / mouseWheelstep >= ScaleMin) ||
                    (!MoveOverEnabled && calc_ScaleX / mouseWheelstep >= scaleMinByNoMoveOver && calc_ScaleY / mouseWheelstep >= scaleMinByNoMoveOver))
                {
                    double px = mousePoint.X - calc_CanvasX;
                    double py = mousePoint.Y - calc_CanvasY;
                    double px_add = px * (1.0 - 1.0 / mouseWheelstep);
                    double py_add = py * (1.0 - 1.0 / mouseWheelstep);
                    sX = calc_ScaleX / mouseWheelstep;
                    sY = calc_ScaleY / mouseWheelstep;
                    cX = calc_CanvasX + px_add;
                    cY = calc_CanvasY + py_add;
                    if (AnimationEnabled)
                    {
                        if (scaleStoryBoard == null)
                        {
                            scaleStoryBoard = new Storyboard();
                            scaleStoryBoard.Completed += ScaleStoryBoard_Completed;
                        }
                        else
                        {
                            scaleStoryBoard.Stop();
                            //CanvasX = calc_CanvasX;
                            //CanvasY = calc_CanvasY;
                            ScaleX = calc_ScaleX;
                            ScaleY = calc_ScaleY;
                            scaleStoryBoard.Children.Clear();
                        }
                        calc_ScaleX = sX;
                        calc_ScaleY = sY;
                        calc_CanvasX = cX;
                        calc_CanvasY = cY;
                        List<DoubleAnimation> animations = CreateAnimationByScale();
                        foreach (var item in animations)
                        {
                            scaleStoryBoard.Children.Add(item);

                        }
                        scaleStoryBoard.Begin(this, true);
                    }
                    else
                    {
                        calc_CanvasX = CanvasX = cX;
                        calc_CanvasY = CanvasY = cY;
                        calc_ScaleX = ScaleX = sX;
                        calc_ScaleY = ScaleY = sY;
                    }
                    scaleChangeTimes--;

                    Canvas.SetLeft(Rect_Mapping, -cX / sX * MappingWidth / ImageWidth);
                    Canvas.SetTop(Rect_Mapping, -cY / sY * MappingHeight / ImageHeight);
                    Rect_Mapping.Width = MappingWidth * showAreaActualWidth / sX / ImageWidth;
                    Rect_Mapping.Height = MappingHeight * showAreaActualHeight / sY / ImageHeight;
                    if (Rect_Mapping.Width > MappingWidth || Rect_Mapping.Height > MappingHeight)
                        MappingVisit = Visibility.Collapsed;
                    else
                        MappingVisit = Visibility.Visible;

                    if (Math.Abs(scaleChangeTimes) >= DecodeChangeByScaleCount)
                    {
                        switch (LoadModel)
                        {
                            case ImageLoadModelEnum.正常:
                                if (AutoDecodePixelEnabled)
                                    ImageRefush(false);
                                break;
                            case ImageLoadModelEnum.瓦片:
                                TileRefush(new Point(showAreaActualWidth / 2, showAreaActualHeight / 2), (int)(ImageWidth * sX), true);
                                break;
                        }
                        scaleChangeTimes = 0;
                    }
                }
                else
                    return;
            }
            ImageScale = sX / orgScaleX;
        }

        private List<DoubleAnimation> CreateAnimationByScale()
        {
            List<DoubleAnimation> animations = new List<DoubleAnimation>();
            DoubleAnimation scaleXAniamtion = new DoubleAnimation()
            {
                From = ScaleX,
                To = calc_ScaleX,
                Duration = new Duration(new TimeSpan(0, 0, 0, 0, 300)),
                AccelerationRatio = 0.3,
                FillBehavior = FillBehavior.Stop,
                AutoReverse = false
            };
            Storyboard.SetTarget(scaleXAniamtion, this);
            Storyboard.SetTargetProperty(scaleXAniamtion, new PropertyPath("ScaleX"));
            animations.Add(scaleXAniamtion);
            DoubleAnimation scaleYAniamtion = new DoubleAnimation()
            {
                From = ScaleY,
                To = calc_ScaleY,
                Duration = new Duration(new TimeSpan(0, 0, 0, 0, 300)),
                AccelerationRatio = 0.3,
                FillBehavior = FillBehavior.Stop,
                AutoReverse = false
            };
            Storyboard.SetTarget(scaleYAniamtion, this);
            Storyboard.SetTargetProperty(scaleYAniamtion, new PropertyPath("ScaleY"));
            animations.Add(scaleYAniamtion);
            DoubleAnimation canvasXAniamtion = new DoubleAnimation()
            {
                From = CanvasX,
                To = calc_CanvasX,
                Duration = new Duration(new TimeSpan(0, 0, 0, 0, 300)),
                AccelerationRatio = 0.3,
                FillBehavior = FillBehavior.Stop,
                AutoReverse = false
            };
            Storyboard.SetTarget(canvasXAniamtion, this);
            Storyboard.SetTargetProperty(canvasXAniamtion, new PropertyPath("CanvasX"));
            animations.Add(canvasXAniamtion);
            DoubleAnimation canvasYAniamtion = new DoubleAnimation()
            {
                From = CanvasY,
                To = calc_CanvasY,
                Duration = new Duration(new TimeSpan(0, 0, 0, 0, 300)),
                AccelerationRatio = 0.3,
                FillBehavior = FillBehavior.Stop,
                AutoReverse = false
            };
            Storyboard.SetTarget(canvasYAniamtion, this);
            Storyboard.SetTargetProperty(canvasYAniamtion, new PropertyPath("CanvasY"));
            animations.Add(canvasYAniamtion);
            return animations;
        }

        private void ScaleStoryBoard_Completed(object sender, EventArgs e)
        {
            CanvasX = calc_CanvasX;
            CanvasY = calc_CanvasY;
            ScaleX = calc_ScaleX;
            ScaleY = calc_ScaleY;
            scaleStoryBoard.Children.Clear();
        }

        /// <summary>
        /// 获取图像路径处理
        /// </summary>
        private void GetImagePath()
        {
            back_ImagePath = ImagePath;
            back_TileColumns = TileColumns;
            back_TileRows = TileRows;
            back_CacheLastImage = CacheLastImage;
            tileSrcMat?.Dispose();
            if (ImageData != null) ImageData = null;
            if (!File.Exists(ImagePath)) return;
            switch (LoadModel)
            {
                case ImageLoadModelEnum.正常:
                    using (FileStream fs = new FileStream(ImagePath, FileMode.Open, FileAccess.Read))
                    {
                        byte[] data = new byte[fs.Length];
                        fs.Read(data, 0, data.Length);
                        ImageData = data;
                    }
                    break;
                case ImageLoadModelEnum.瓦片:
                    TileInitRefush();
                    ImageSizeChanged();
                    break;
                case ImageLoadModelEnum.位图:
                    BitPixelRefush();
                    break;
            }
        }

        /// <summary>
        /// 编辑状态更变处理
        /// </summary>
        private void StatusChanged()
        {
            switch (Status)
            {
                case ImageStatusEnum.选点:
                    this.Cursor = Cursors.Hand;
                    break;
                default:
                    this.Cursor = Cursors.Arrow;
                    break;
            }
        }

        /// <summary>
        /// 初始化图像显示控件集合
        /// </summary>
        private void InitImageList()
        {
            if (ImageList != null && !back_CacheLastImage)
            {
                foreach (var image in ImageList)
                {
                    if (image.Source != null && image.Source != null)
                    {
                        if (image.Source is BitmapImage)
                        {
                            (image.Source as BitmapImage).StreamSource.Dispose();
                            (image.Source as BitmapImage).StreamSource = null;
                            image.Source = null;
                        }
                    }
                }
                ImageList.Clear();
            }
            if (ImageList == null || back_CacheLastImage)
                ImageList = new ObservableCollection<Image>();
            if (SketchImageSource != null)
                SketchImageSource.StreamSource?.Dispose();
            if (MappingSource != null)
                MappingSource.StreamSource?.Dispose();
        }

        /// <summary>
        /// 图像尺寸变化处理
        /// </summary>
        private void ImageSizeChanged()
        {
            if (ActualHeight <= 0 || ActualWidth <= 0) return;
            if (RulerVisit == Visibility.Visible)
            {
                showAreaActualWidth = ActualWidth - 30;
                showAreaActualHeight = ActualHeight - 30;

            }
            else
            {
                showAreaActualWidth = ActualWidth;
                showAreaActualHeight = ActualHeight;
            }
            CanvasX = calc_CanvasX = 0;
            CanvasY = calc_CanvasY = 0;
            Angle = 0;
            if (ImageWidth == 0 || ImageHeight == 0) return;
            double xRad = showAreaActualWidth / ImageWidth;
            double yRad = showAreaActualHeight / ImageHeight;

            switch (Stretch)
            {
                case Stretch.None:
                    ScaleX = 1.0;
                    ScaleY = 1.0;
                    break;
                case Stretch.Fill:
                    ScaleX = showAreaActualWidth / ImageWidth;
                    ScaleY = showAreaActualHeight / ImageHeight;
                    break;
                case Stretch.Uniform:
                    if (MoveOverEnabled)
                        ScaleX = ScaleY = xRad > yRad ? yRad : xRad;
                    else
                        ScaleX = ScaleY = xRad < yRad ? yRad : xRad;
                    break;
                case Stretch.UniformToFill:
                    if (MoveOverEnabled)
                        ScaleX = ScaleY = xRad > yRad ? xRad : yRad;
                    else
                        ScaleX = ScaleY = xRad < yRad ? xRad : yRad;
                    break;
            }
            orgScaleX = calc_ScaleX = ScaleX;
            orgScaleY = calc_ScaleY = ScaleY;
            if (LitmitScaleMin)
                ScaleMin = orgScaleX;
            orgX = calc_CanvasX = CanvasX = (showAreaActualWidth - ImageWidth * calc_ScaleX) / 2;
            orgY = calc_CanvasY = CanvasY = (showAreaActualHeight - ImageHeight * calc_ScaleY) / 2;
            if (MoveOverEnabled)
                scaleMinByNoMoveOver = ScaleMin;
            else
                scaleMinByNoMoveOver = xRad > yRad ? xRad : yRad;
        }

        /// <summary>
        /// 基于图像字节数据获取图像类型
        /// </summary>
        /// <param name="data">图像byte数组</param>
        /// <returns></returns>
        private string GetImageFormatByByteArray(byte[] data)
        {
            if (data == null || data.Length < 10)
                return string.Empty;
            if (data[0] == 71 && data[1] == 73 && data[2] == 70)
                return "Gif";
            else if (data[1] == 80 && data[2] == 78 && data[3] == 71)
                return "Png";
            else if (data[6] == 74 && data[7] == 70 && data[8] == 73 && data[9] == 70)
                return "Jpg";
            else if (data[0] == 66 && data[1] == 77)
                return "Bmp";
            return "Jpg";
        }

        /// <summary>
        /// 手动缩放处理
        /// </summary>
        private void ManualScaleChanged()
        {
            if (MouseWheelEnabled || ManualScale == lastManualScale) return;
            Point point = new Point(showAreaActualWidth / 2, showAreaActualHeight / 2);
            double delta = ManualScale / lastManualScale;
            lastManualScale = ManualScale;
            double sX = 1.0, sY = 1.0, cX = 0.0, cY = 0.0;
            if (delta > 1)
            {
                if (calc_ScaleX * delta <= ScaleMax && calc_ScaleY * delta <= ScaleMax)
                {
                    double px = point.X - calc_CanvasX;
                    double py = point.Y - calc_CanvasY;
                    double px_add = px * (delta - 1.0);
                    double py_add = py * (delta - 1.0);
                    sX = calc_ScaleX * delta;
                    sY = calc_ScaleY * delta;
                    cX = calc_CanvasX - px_add;
                    cY = calc_CanvasY - py_add;
                    if (AnimationEnabled)
                    {
                        if (scaleStoryBoard == null)
                        {
                            scaleStoryBoard = new Storyboard();
                            scaleStoryBoard.Completed += ScaleStoryBoard_Completed;
                        }
                        else
                        {
                            scaleStoryBoard.Stop();
                            ScaleX = calc_ScaleX;
                            ScaleY = calc_ScaleY;
                            scaleStoryBoard.Children.Clear();
                        }
                        calc_ScaleX = sX;
                        calc_ScaleY = sY;
                        calc_CanvasX = cX;
                        calc_CanvasY = cY;
                        List<DoubleAnimation> animations = CreateAnimationByScale();
                        foreach (var item in animations)
                        {
                            scaleStoryBoard.Children.Add(item);

                        }
                        scaleStoryBoard.Begin(this, true);
                    }
                    else
                    {
                        calc_CanvasX = CanvasX = cX;
                        calc_CanvasY = CanvasY = cY;
                        calc_ScaleX = ScaleX = sX;
                        calc_ScaleY = ScaleY = sY;
                    }
                    Canvas.SetLeft(Rect_Mapping, -cX / sX * MappingWidth / ImageWidth);
                    Canvas.SetTop(Rect_Mapping, -cY / sY * MappingHeight / ImageHeight);
                    Rect_Mapping.Width = MappingWidth * showAreaActualWidth / sX / ImageWidth;
                    Rect_Mapping.Height = MappingHeight * showAreaActualHeight / sY / ImageHeight;
                    if (Rect_Mapping.Width > MappingWidth || Rect_Mapping.Height > MappingHeight)
                        MappingVisit = Visibility.Collapsed;
                    else
                        MappingVisit = Visibility.Visible;

                        switch (LoadModel)
                        {
                            case ImageLoadModelEnum.正常:
                                if (AutoDecodePixelEnabled)
                                    ImageRefush(false);
                                break;
                            case ImageLoadModelEnum.瓦片:
                                TileRefush(new Point(showAreaActualWidth / 2, showAreaActualHeight / 2), (int)(ImageWidth * sX), true);
                                break;
                        }
                        scaleChangeTimes = 0;
                }
                else
                    return;
            }
            else
            {
                if ((MoveOverEnabled && calc_ScaleX / delta >= ScaleMin && calc_ScaleY / delta >= ScaleMin) ||
                    (!MoveOverEnabled && calc_ScaleX / delta >= scaleMinByNoMoveOver && calc_ScaleY / delta >= scaleMinByNoMoveOver))
                {
                    double px = point.X - calc_CanvasX;
                    double py = point.Y - calc_CanvasY;
                    double px_add = px * (1.0 - delta);
                    double py_add = py * (1.0 - delta);
                    sX = calc_ScaleX / (1 / delta);
                    sY = calc_ScaleY / (1 / delta);
                    cX = calc_CanvasX + px_add;
                    cY = calc_CanvasY + py_add;
                    if (AnimationEnabled)
                    {
                        if (scaleStoryBoard == null)
                        {
                            scaleStoryBoard = new Storyboard();
                            scaleStoryBoard.Completed += ScaleStoryBoard_Completed;
                        }
                        else
                        {
                            scaleStoryBoard.Stop();
                            ScaleX = calc_ScaleX;
                            ScaleY = calc_ScaleY;
                            scaleStoryBoard.Children.Clear();
                        }
                        calc_ScaleX = sX;
                        calc_ScaleY = sY;
                        calc_CanvasX = cX;
                        calc_CanvasY = cY;
                        List<DoubleAnimation> animations = CreateAnimationByScale();
                        foreach (var item in animations)
                        {
                            scaleStoryBoard.Children.Add(item);

                        }
                        scaleStoryBoard.Begin(this, true);
                    }
                    else
                    {
                        calc_CanvasX = CanvasX = cX;
                        calc_CanvasY = CanvasY = cY;
                        calc_ScaleX = ScaleX = sX;
                        calc_ScaleY = ScaleY = sY;
                    }

                    Canvas.SetLeft(Rect_Mapping, -cX / sX * MappingWidth / ImageWidth);
                    Canvas.SetTop(Rect_Mapping, -cY / sY * MappingHeight / ImageHeight);
                    Rect_Mapping.Width = MappingWidth * showAreaActualWidth / sX / ImageWidth;
                    Rect_Mapping.Height = MappingHeight * showAreaActualHeight / sY / ImageHeight;
                    if (Rect_Mapping.Width > MappingWidth || Rect_Mapping.Height > MappingHeight)
                        MappingVisit = Visibility.Collapsed;
                    else
                        MappingVisit = Visibility.Visible;
                    switch (LoadModel)
                    {
                        case ImageLoadModelEnum.正常:
                            if (AutoDecodePixelEnabled)
                                ImageRefush(false);
                            break;
                        case ImageLoadModelEnum.瓦片:
                            TileRefush(new Point(showAreaActualWidth / 2, showAreaActualHeight / 2), (int)(ImageWidth * sX), true);
                            break;
                    }
                }
                else
                    return;
            }
            ImageScale = ManualScale;

        }
        #endregion

        #region 位图模式
        /// <summary>
        /// 位图模式下获取图像Mat
        /// </summary>
        /// <param name="mat"></param>
        public void GetMat(Mat mat)
        {
            if (LoadModel != ImageLoadModelEnum.位图)
            {
                mat?.Dispose();
                return;
            }
            ImageWidth = mat.Width;
            ImageHeight = mat.Height;
            back_ImageWidth = mat.Width;
            back_ImageHeight = mat.Height;
            back_Dirty_X = Dirty_X;
            back_Dirty_Y = Dirty_Y;
            back_Dirty_Width = Dirty_Width;
            back_Dirty_Height = Dirty_Height;
            if (IsSTA)
                GetMatBySTA(mat, back_Dirty_X, back_Dirty_Y, back_Dirty_Width, back_Dirty_Height);
            else
                GetMatByNotSTA(mat, back_Dirty_X, back_Dirty_Y, back_Dirty_Width, back_Dirty_Height);

        }

        /// <summary>
        /// 独立STA处理位图Mat
        /// </summary>
        /// <param name="mat"></param>
        /// <param name="back_Dirty_X"></param>
        /// <param name="back_Dirty_Y"></param>
        /// <param name="back_Dirty_Width"></param>
        /// <param name="back_Dirty_Height"></param>
        private void GetMatBySTA(Mat mat, int back_Dirty_X, int back_Dirty_Y, int back_Dirty_Width, int back_Dirty_Height)
        {
            bool sizeChanged = false;
            var curFormat = mat.Type() == MatType.CV_8UC1 ? PixelFormats.Gray8 : PixelFormats.Bgr32;
            if (staImage == null)
            {
                format = curFormat;
                InitSTAImage();
                sizeChanged = true;
            }
            else
            {
                staImage.Dispatcher.Invoke(new Action(() =>
                {
                    if (staImage.Width != back_ImageWidth || staImage.Height != back_ImageHeight || format != curFormat)
                    {
                        format = curFormat;
                        staImage.Width = back_ImageWidth;
                        staImage.Height = back_ImageHeight;
                        sizeChanged = true;
                    }
                }));
            }

            Task.Run(() =>
            {
                var bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
                var bitData = bitmap.LockBits(new System.Drawing.Rectangle(new System.Drawing.Point(0, 0), bitmap.Size), System.Drawing.Imaging.ImageLockMode.ReadOnly,
                        format.BitsPerPixel == 8 ? System.Drawing.Imaging.PixelFormat.Format8bppIndexed : System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                staImage.Dispatcher.BeginInvoke(new Action(() =>
                {
                    WriteableBitmap wb = staImage.Source as WriteableBitmap;
                    if (wb == null || sizeChanged)
                    {
                        Console.WriteLine("WB Start Init");
                        wb = new WriteableBitmap(mat.Width, mat.Height, 0, 0, format, null);
                        staImage.Source = wb;
                        Console.WriteLine("WB Init");
                    }
                    wb.Lock();
                    if (back_Dirty_X >= 0 && back_Dirty_Y >= 0 && back_Dirty_Width > 0 && back_Dirty_Height > 0)
                    {
                        wb.WritePixels(new Int32Rect(back_Dirty_X, back_Dirty_Y, back_Dirty_Width, back_Dirty_Height), bitData.Scan0, bitData.Height * bitData.Stride, bitData.Stride, back_Dirty_X, back_Dirty_Y);
                        wb.AddDirtyRect(new Int32Rect(back_Dirty_X, back_Dirty_Y, back_Dirty_Width, back_Dirty_Height));
                    }
                    else
                        wb.WritePixels(new Int32Rect(0, 0, bitmap.Width, bitmap.Height), bitData.Scan0, bitData.Height * bitData.Stride, bitData.Stride, 0, 0);
                    wb.Unlock();
                    Task.Run(() =>
                    {
                        bitmap.UnlockBits(bitData);
                        mat?.Dispose();
                    });
                }));
                if (sizeChanged)
                {
                    this.Dispatcher.Invoke(new Action(() =>
                    {
                        Console.WriteLine("SizeChaged Start");
                        ImageSizeChanged();
                        Console.WriteLine("SizeChaged OK");
                    }));
                }
     
            });

        }

        /// <summary>
        /// 初始化STA线程所属图像控件
        /// </summary>
        private void InitSTAImage()
        {
            var oldContent = this.STA_Content.Content as Image;
            if (oldContent != null)
            {
                Console.WriteLine("STADispose");
                oldContent.Source = null;
            }
            HostVisual hostVisual = new HostVisual();
            UIElement content = new VisualHost_IS(hostVisual);
            this.STA_Content.Content = content;
                    UpdateLayout();
            Thread staThread = new Thread(new ThreadStart(() =>
            {
                VisualTarget visualTarget = new VisualTarget(hostVisual);
                staImage = new Image();
                staImage.Width = back_ImageWidth;
                staImage.Height = back_ImageHeight;
                staImage.Arrange(new Rect(new Point(), content.RenderSize));
                visualTarget.RootVisual = staImage;
                Console.WriteLine("STAOK");
                System.Windows.Threading.Dispatcher.Run();
            }));
            staThread.IsBackground = true;
            staThread.SetApartmentState(ApartmentState.STA);
            staThread.Start();
        }

        /// <summary>
        /// 非独立STA处理位图Mat
        /// </summary>
        /// <param name="mat"></param>
        /// <param name="back_Dirty_X"></param>
        /// <param name="back_Dirty_Y"></param>
        /// <param name="back_Dirty_Width"></param>
        /// <param name="back_Dirty_Height"></param>
        private void GetMatByNotSTA(Mat mat, int back_Dirty_X, int back_Dirty_Y, int back_Dirty_Width, int back_Dirty_Height)
        {
            var curFormat = mat.Type() == MatType.CV_8UC1 ? PixelFormats.Gray8 : PixelFormats.Bgr32;
            bool sizeChanged = false;
            if (ImageList == null) ImageList = new ObservableCollection<Image>();
            Image image = ImageList.FirstOrDefault();
            if (image == null || image.Width != ImageWidth || image.Height != ImageHeight || format != curFormat)
            {
                format = curFormat;
                InitImageList();
                image = new Image();
                image.Width = ImageWidth;
                image.Height = ImageHeight;
                ImageList.Add(image);
                sizeChanged = true;
            }
            Task.Run(() =>
            {
                var bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
                var bitData = bitmap.LockBits(new System.Drawing.Rectangle(new System.Drawing.Point(0, 0), bitmap.Size), System.Drawing.Imaging.ImageLockMode.ReadOnly,
                        format.BitsPerPixel == 8 ? System.Drawing.Imaging.PixelFormat.Format8bppIndexed : System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                this.Dispatcher.Invoke(new Action(() =>
                {
                    WriteableBitmap wb = image.Source as WriteableBitmap;
                    if (wb == null)
                    {
                        wb = new WriteableBitmap(mat.Width, mat.Height, 0, 0, format, null);
                        image.Source = wb;
                    }
                    wb.Lock();
                    if (back_Dirty_X >= 0 && back_Dirty_Y >= 0 && back_Dirty_Width > 0 && back_Dirty_Height > 0)
                    {
                        wb.WritePixels(new Int32Rect(back_Dirty_X, back_Dirty_Y, back_Dirty_Width, back_Dirty_Height), bitData.Scan0, bitData.Height * bitData.Stride, bitData.Stride, back_Dirty_X, back_Dirty_Y);
                        wb.AddDirtyRect(new Int32Rect(back_Dirty_X, back_Dirty_Y, back_Dirty_Width, back_Dirty_Height));
                    }
                    else
                        wb.WritePixels(new Int32Rect(0, 0, bitmap.Width, bitmap.Height), bitData.Scan0, bitData.Height * bitData.Stride, bitData.Stride, 0, 0);
                    wb.Unlock();
                    if (sizeChanged)
                    {
                        ImageSizeChanged();
                    }
                }));
                bitmap.UnlockBits(bitData);
                mat?.Dispose();
            });
        }

        /// <summary>
        /// 位图模式下通过图片路径刷新图片
        /// </summary>
        /// <param name="flag"></param>
        private void BitPixelRefush(bool flag = true)
        {
            string back_ImagePath = ImagePath;
            fastFrame = null;
            switch (System.IO.Path.GetExtension(ImagePath).ToUpper())
            {
                case ".JPG":
                    fastFrame = new JpegBitmapDecoder(new Uri(ImagePath), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand).Frames[0];
                    break;
                case ".BMP":
                    fastFrame = new BmpBitmapDecoder(new Uri(ImagePath), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand).Frames[0];
                    break;
                case ".PNG":
                    fastFrame = new PngBitmapDecoder(new Uri(ImagePath), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand).Frames[0];
                    break;
                case ".GIT":
                    fastFrame = new GifBitmapDecoder(new Uri(ImagePath), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand).Frames[0];
                    break;
                default:
                    fastFrame = new JpegBitmapDecoder(new Uri(ImagePath), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand).Frames[0];
                    break;
            }
            ImageWidth = fastFrame.PixelWidth;
            ImageHeight = fastFrame.PixelHeight;
            if (ImageList == null) ImageList = new ObservableCollection<Image>();
            Image image = ImageList.FirstOrDefault();
            bool sizeChanged = false;
            if (image == null || image.Width != ImageWidth || image.Height != ImageHeight || format != fastFrame.Format)
            {
                format = fastFrame.Format;
                InitImageList();
                image = new Image();
                image.Width = ImageWidth;
                image.Height = ImageHeight;
                ImageList.Add(image);
                sizeChanged = true;
            }
            Task.Run(() =>
            {
                using (Mat mat = new Mat(back_ImagePath, ImreadModes.Unchanged))
                {
                    var bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
                    var bitData = bitmap.LockBits(new System.Drawing.Rectangle(new System.Drawing.Point(0, 0), bitmap.Size), System.Drawing.Imaging.ImageLockMode.ReadOnly,
                            format.BitsPerPixel == 8 ? System.Drawing.Imaging.PixelFormat.Format8bppIndexed : System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                    this.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        WriteableBitmap wb = image.Source as WriteableBitmap;
                        if (wb == null)
                        {
                            wb = new WriteableBitmap(mat.Width, mat.Height, 0, 0, format, null);
                            image.Source = wb;
                        }
                        wb.Lock();
                        wb.WritePixels(new Int32Rect(0, 0, bitmap.Width, bitmap.Height), bitData.Scan0, bitData.Height * bitData.Stride, bitData.Stride, 0, 0);
                        wb.Unlock();

                        if (sizeChanged)
                        {
                            if (flag)
                                ImageSizeChanged();
                        }
                    }));
                    bitmap.UnlockBits(bitData);
                }
            });
        } 
        #endregion

        #region 快速示意图模式
        /// <summary>
        /// 示意图刷新
        /// </summary>
        private void SketchImageRefush()
        {
            InitImageList();

            SketchRefush();

            ImageSizeChanged();
        }

        /// <summary>
        /// 示意图图像源刷新
        /// </summary>
        private void SketchRefush()
        {
            Image image = new Image();
            var imageSource = new BitmapImage();
            imageSource.BeginInit();
            imageSource.StreamSource = new MemoryStream(SketchByte);
            imageSource.EndInit();
            ImageSource = imageSource;
            image.Source = imageSource;
            image.Width = ImageWidth;
            image.Height = ImageHeight;
            ImageList.Add(image);
        }
        #endregion

        #region 正常模式
        /// <summary>
        /// 图像刷新处理
        /// </summary>
        private void ImageRefush(bool flag = true)
        {
            back_ImagePath = ImagePath;
            back_TileColumns = TileColumns;
            back_TileRows = TileRows;
            back_CacheLastImage = CacheLastImage;

            if ((int)(ImageWidth * ScaleX) > ImageWidth && AutoDecodePixelEnabled) return;
            InitImageList();
            NormalRefush();

            if (flag)
                ImageSizeChanged();
        }

        /// <summary>
        /// 正常模式刷新
        /// </summary>
        private void NormalRefush()
        {
            Image image = new Image();
            if (ImageData == null) return;

            if (MappingEnabled)
            {
                Task.Run(() =>
                {
                    this.Dispatcher.Invoke(new Action(() =>
                    {
                        if (MappingSource != null)
                            MappingSource.StreamSource?.Dispose();
                    }));
                    var mappingSource = new BitmapImage();
                    mappingSource.BeginInit();
                    mappingSource.CacheOption = BitmapCacheOption.OnLoad;
                    mappingSource.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
                    mappingSource.DecodePixelWidth = 540;
                    mappingSource.UriSource = new Uri(back_ImagePath);
                    mappingSource.EndInit();
                    mappingSource.Freeze();
                    this.Dispatcher.Invoke(new Action(() =>
                    {
                        MappingSource = mappingSource;
                    }));
                });
                
            }

            var imageSource = new BitmapImage();
            imageSource.BeginInit();
            imageSource.StreamSource = new MemoryStream(ImageData);
            if (DecodePixelEnabled)
            {
                BitmapFrame frame;
                using (MemoryStream stream = new MemoryStream(ImageData))
                {
                    switch (GetImageFormatByByteArray(ImageData))
                    {
                        case "Jpg":
                            frame = new JpegBitmapDecoder(stream, BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand).Frames[0];
                            break;
                        case "Bmp":
                            frame = new BmpBitmapDecoder(stream, BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand).Frames[0];
                            break;
                        case "Png":
                            frame = new PngBitmapDecoder(stream, BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand).Frames[0];
                            break;
                        case "Gif":
                            frame = new GifBitmapDecoder(stream, BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand).Frames[0];
                            break;
                        default:
                            frame = new JpegBitmapDecoder(stream, BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand).Frames[0];
                            break;
                    }
                    ImageWidth = frame.PixelWidth;
                    ImageHeight = frame.PixelHeight;
                }
                if (AutoDecodePixelEnabled)
                    imageSource.DecodePixelWidth = (int)(ImageWidth * ScaleX);
                else
                    imageSource.DecodePixelWidth = DecodePixelValue;
            }
            imageSource.EndInit();
            if (!DecodePixelEnabled)
            {
                ImageWidth = imageSource.PixelWidth;
                ImageHeight = imageSource.PixelHeight;
            }
            ImageSource = imageSource;
            image.Source = imageSource;
            image.Width = ImageWidth;
            image.Height = ImageHeight;
            ImageList.Add(image);
        } 
        #endregion

        #region 瓦片模式
        /// <summary>
        /// 根据像素解析度加载示意图(瓦片模式)
        /// </summary>
        /// <param name="decodeValue"></param>
        private void LoadSketchImage(int decodeValue)
        {
            Stopwatch sw = Stopwatch.StartNew();
            this.Dispatcher.Invoke(new Action(() =>
            {
                if (SketchImageSource != null)
                    SketchImageSource.StreamSource?.Dispose();
                if (MappingSource != null)
                    MappingSource.StreamSource?.Dispose();
            }));
            var imageSource = new BitmapImage();
            imageSource.BeginInit();
            imageSource.CacheOption = BitmapCacheOption.OnLoad;
            imageSource.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
            imageSource.DecodePixelWidth = decodeValue;
            imageSource.UriSource = new Uri(back_ImagePath);
            imageSource.EndInit();
            imageSource.Freeze();
            Console.WriteLine($"示意图加载耗时 {sw.ElapsedMilliseconds} ms ");
            this.Dispatcher.Invoke(new Action(() =>
            {
                SketchImageSource = imageSource;
                MappingSource = imageSource;
            }));
            sw.Stop();
            Console.WriteLine($"示意图显示耗时 {sw.ElapsedMilliseconds} ms ");
            //ImageSizeChanged();
        }

        /// <summary>
        /// 初始化瓦片刷新
        /// </summary>
        private void TileInitRefush()
        {
            fastFrame = null;
            switch (System.IO.Path.GetExtension(ImagePath).ToUpper())
            {
                case ".JPG":
                    fastFrame = new JpegBitmapDecoder(new Uri(ImagePath), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand).Frames[0];
                    break;
                case ".BMP":
                    fastFrame = new BmpBitmapDecoder(new Uri(ImagePath), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand).Frames[0];
                    break;
                case ".PNG":
                    fastFrame = new PngBitmapDecoder(new Uri(ImagePath), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand).Frames[0];
                    break;
                case ".GIT":
                    fastFrame = new GifBitmapDecoder(new Uri(ImagePath), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand).Frames[0];
                    break;
                default:
                    fastFrame = new JpegBitmapDecoder(new Uri(ImagePath), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand).Frames[0];
                    break;
            }
            ImageWidth = fastFrame.PixelWidth;
            ImageHeight = fastFrame.PixelHeight;
            format = fastFrame.Format;

            ImageSizeChanged();
            InitImageList();
            List<Task> tasks = new List<Task>();
            HandTip = "示意图加载中。。。。。。";
            HandTipVisit = Visibility.Visible;
            int decodeValue = DecodePixelValue;
            Task.Run(() =>
            {
                LoadSketchImage(decodeValue);
                this.Dispatcher.Invoke(new Action(() =>
                {
                    HandTip = "示意图加载完成，正在处理完整图片数据，处理结束后可查看高清图片。。。。。。";
                }));
                Stopwatch sw = Stopwatch.StartNew();
                tileSrcMat = new Mat(back_ImagePath, ImreadModes.Unchanged);
                sw.Stop();
                Console.WriteLine($"Mat读取原图{sw.ElapsedMilliseconds}");
                this.Dispatcher.Invoke(new Action(() =>
                {
                    HandTipVisit = Visibility.Collapsed;
                }));
            });
        }

        /// <summary>
        /// 创建图像显示控件(瓦片模式)
        /// </summary>
        /// <param name="source"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="startX"></param>
        /// <param name="startY"></param>
        /// <returns></returns>
        private string CreateImage(Mat source, int x, int y, int width, int height, int startX = 0, int startY = 0)
        {
            string key = Guid.NewGuid().GetHashCode().ToString();
            int xFlag = source.Width % back_TileColumns;
            int yFlag = source.Height % back_TileRows;
            int pWidth = source.Width;
            int pHeight = source.Height;
            this.Dispatcher.Invoke(new Action(() =>
            {
                Image image = new Image() { Tag = key, Visibility = Visibility.Collapsed, UseLayoutRounding = false, SnapsToDevicePixels = true };
                image.Width = (int)(width / back_TileColumns + (((back_TileColumns - 1 - x) < xFlag) ? 1 : 0));
                image.Height = (int)(height / back_TileRows + (((back_TileRows - 1 - y) < yFlag) ? 1 : 0));
                ImageList.Add(image);
                var offX = 0;
                for (int i = 0; i < x; i++)
                {
                    offX += (((back_TileColumns - 1 - i) < xFlag) ? 1 : 0);
                }
                var canvasX = (int)(width / back_TileColumns * x + offX);
                var offY = 0;
                for (int i = 0; i < y; i++)
                {
                    offY += (((back_TileRows - 1 - i) < yFlag) ? 1 : 0);
                }
                var canvasY = (int)(height / back_TileRows * y + offY);
                Canvas.SetLeft(image, canvasX + startX);
                Canvas.SetTop(image, canvasY + startY);
            }));

            return key;
        }

        /// <summary>
        /// 创建图像Bitmap(瓦片模式)
        /// </summary>
        /// <param name="source"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="key"></param>
        private void CreateBitmap(Mat source, int x, int y, string key)
        {

            Stopwatch stopwatch = Stopwatch.StartNew();
            int index = imageKeyList.IndexOf(key);
            if (index < 0) return;
            int pWidth = source.Width;
            int pHeight = source.Height;
            int xFlag = pWidth % back_TileColumns;
            int yFlag = pHeight % back_TileRows;

            var offX = 0;
            for (int i = 0; i < x; i++)
            {
                offX += (((back_TileColumns - 1 - i) < xFlag) ? 1 : 0);
            }
            var offY = 0;
            for (int i = 0; i < y; i++)
            {
                offY += (((back_TileRows - 1 - i) < yFlag) ? 1 : 0);
            }

            using (Mat curMat = new Mat(source, new OpenCvSharp.Rect((int)(pWidth / back_TileColumns * x + offX), (int)(pHeight / back_TileRows * y + offY),
                    (int)(pWidth / back_TileColumns + (((back_TileColumns - 1 - x) < xFlag) ? 1 : 0)), (int)(pHeight / back_TileRows + (((back_TileRows - 1 - y) < yFlag) ? 1 : 0)))))
            {
                var stride = format.BitsPerPixel * curMat.Width / 8;
                var bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(curMat);
                var bitData = bitmap.LockBits(new System.Drawing.Rectangle(new System.Drawing.Point(0, 0), bitmap.Size), System.Drawing.Imaging.ImageLockMode.ReadOnly,
                        format.BitsPerPixel == 8 ? System.Drawing.Imaging.PixelFormat.Format8bppIndexed : System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                this.Dispatcher.Invoke(new Action(() =>
                    {

                        if (ImageList.Count > index)
                        {
                            WriteableBitmap wb = new WriteableBitmap(bitmap.Width, bitmap.Height, 0, 0, format, null);
                            ImageList[index].Source = wb;
                            wb.Lock();
                            wb.WritePixels(new Int32Rect(0, 0, bitmap.Width, bitmap.Height), bitData.Scan0, bitData.Height * bitData.Stride, bitData.Stride, 0, 0);

                            wb.Unlock();
                            ImageList[index].Visibility = Visibility.Visible;
                        }
                    }));
            }
            stopwatch.Stop();
            Console.WriteLine($"生成WriteableBitmap {stopwatch.ElapsedMilliseconds}ms");
        }

        /// <summary>
        /// 瓦片刷新数据生成
        /// </summary>
        /// <param name="mousePoint"></param>
        /// <param name="lastDecode"></param>
        /// <param name="flag"></param>
        private void TileRefush(Point mousePoint, int lastDecode, bool flag = false)
        {
            double sX = ScaleX, sY = ScaleY;
            if (AnimationEnabled)
            {
                sX = calc_ScaleX;
                sY = calc_ScaleY;
            }
            int decodeWidth = (int)(ImageWidth * sX) / 2;
            int decodeHeight = (int)(ImageHeight * sY) / 2;

            if (lastDecode >= ImageWidth && !flag) return;
            if (decodeWidth > ImageWidth) decodeWidth = (int)ImageWidth;
            if (decodeHeight > ImageHeight) decodeHeight = (int)ImageHeight;

            int screenWidth = (int)(showAreaActualWidth / sX) + (showAreaActualWidth % sX > 0 ? 1 : 0);
            int screenHeight = (int)(showAreaActualHeight / sY) + (showAreaActualHeight % sY > 0 ? 1 : 0);
            if ((screenWidth > ImageWidth || screenHeight > ImageHeight) && !flag) return;
            GetStartXAndCutWidth(mousePoint, screenWidth, out int cutWidth, out int startX);
            GetStartYAndCutHeight(mousePoint, screenHeight, out int cutHeight, out int startY);
            BackWorkTileModel tile = new BackWorkTileModel()
            {
                ScreenHeight = screenHeight,
                ScreenWidth = screenWidth,
                DecodeWidth = decodeWidth,
                DecodeHeight = decodeHeight,
                StartX = startX,
                StartY = startY,
                CutHeight = cutHeight,
                CutWidth = cutWidth
            };
            if (!back_CacheLastImage)
            {
                ImageList?.Clear();
                imageKeyList?.Clear();
            }
            else if (ImageList != null && ImageList.Count >= TileRows * TileColumns)
            {
                ImageList = new ObservableCollection<Image>(ImageList.Skip(ImageList.Count - 9).Take(TileRows * TileColumns));
                imageKeyList = new List<string>(imageKeyList.Skip(imageKeyList.Count - 9).Take(TileRows * TileColumns));
            }
            tileQueue.Enqueue(tile);
            currentTileKey = tile.Key;
            lastEnqueueTileTime = DateTime.Now;
        }

        /// <summary>
        /// 获取起始X和裁剪宽度(像素)
        /// </summary>
        /// <param name="mousePoint"></param>
        /// <param name="screenWidth"></param>
        /// <param name="cutWidth"></param>
        /// <param name="startX"></param>
        private void GetStartXAndCutWidth(Point mousePoint, int screenWidth, out int cutWidth, out int startX)
        {
            cutWidth = (int)(ImageWidth * ((showAreaActualWidth / ImageWidth) / calc_ScaleX)) + 
                ((ImageWidth * ((showAreaActualWidth / ImageWidth) % calc_ScaleX)) > 0 ? 1 : 0);
            startX = (int)((mousePoint.X - calc_CanvasX) / calc_ScaleX - screenWidth / 2);
            if (startX < 0 && startX + cutWidth > ImageWidth)
            {
                startX = 0;
                cutWidth = (int)ImageWidth;
            }
            else if (startX < 0)
            {
                startX = 0;
            }
            else if (startX + cutWidth > ImageWidth)
            {
                startX = (int)ImageWidth - cutWidth;
                if (startX < 0)
                {
                    startX = 0;
                    cutWidth = (int)ImageWidth;
                }
            }
        }

        /// <summary>
        /// 获取起始Y和裁剪高度
        /// </summary>
        /// <param name="mousePoint"></param>
        /// <param name="screenHeight"></param>
        /// <param name="cutHeight"></param>
        /// <param name="startY"></param>
        private void GetStartYAndCutHeight(Point mousePoint, int screenHeight, out int cutHeight, out int startY)
        {

            cutHeight = (int)(ImageHeight * ((showAreaActualHeight / ImageHeight) / calc_ScaleY)) +
                (ImageHeight * ((showAreaActualHeight / ImageHeight) % calc_ScaleY) > 0 ? 1 : 0);
            startY = (int)((mousePoint.Y - calc_CanvasY) / calc_ScaleY - screenHeight / 2);
            if (startY < 0 && startY + cutHeight > ImageHeight)
            {
                startY = 0;
                cutHeight = (int)ImageHeight;
            }
            else if (startY < 0)
            {
                startY = 0;
            }
            else if (startY + cutHeight > ImageHeight)
            {
                startY = (int)ImageHeight - cutHeight;
                if (startY < 0)
                {
                    startY = 0;
                    cutHeight = (int)ImageHeight;
                }
            }
        }

        /// <summary>
        /// 瓦片刷新任务
        /// </summary>
        private void TileTaskHand()
        {
            while (true)
            {

                try
                {
                    Thread.Sleep(10);
                    if (DateTime.Now - lastEnqueueTileTime < new TimeSpan(0, 0, 0, 0, 100)) continue;
                    if (tileQueue.TryDequeue(out BackWorkTileModel data))
                    {
                        if (data == null || tileQueue.Count > 0) continue;
                        TileHand(data);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }

            }
        }

        /// <summary>
        /// 瓦片刷新实际处理
        /// </summary>
        /// <param name="data"></param>
        private void TileHand(BackWorkTileModel data)
        {
            if (tileSrcMat.IsDisposed) return;
            int widthDecode = data.DecodeWidth * data.CutWidth / tileSrcMat.Width + (data.DecodeWidth * data.CutWidth % tileSrcMat.Width > 0 ? 1 : 0);
            int heightDecode = data.DecodeWidth * data.CutHeight / data.CutWidth * data.CutWidth / tileSrcMat.Width + 
                (data.DecodeWidth * data.CutHeight / data.CutWidth * data.CutWidth % tileSrcMat.Width > 0 ? 1: 0);
            Stopwatch sw = Stopwatch.StartNew();
            using (Mat partMat = new Mat(tileSrcMat, new OpenCvSharp.Rect(data.StartX, data.StartY, data.CutWidth, data.CutHeight)))
            {
                Console.WriteLine($"GetPartImage: {sw.ElapsedMilliseconds}");
                using (Mat mat = new Mat())
                {
                    sw.Restart();
                    Cv2.Resize(partMat, mat, new OpenCvSharp.Size(widthDecode, heightDecode), widthDecode / data.CutWidth, heightDecode / data.CutHeight, InterpolationFlags.Area);
                    sw.Stop();
                    Console.WriteLine($"Resize: {sw.ElapsedMilliseconds}");
                    int offIndex = back_CacheLastImage ? imageKeyList.Count() : 0;
                    for (int x = 0; x < back_TileColumns; x++)
                    {
                        for (int y = 0; y < back_TileRows; y++)
                        {
                            if (data.Key != currentTileKey) break;
                            imageKeyList.Add(CreateImage(mat, x, y, data.CutWidth, data.CutHeight, data.StartX, data.StartY));
                        }
                    }

                    for (int x = 0; x < back_TileColumns; x++)
                    {
                        for (int y = 0; y < back_TileRows; y++)
                        {
                            if (data.Key != currentTileKey) break;
                            CreateBitmap(mat, x, y, imageKeyList[offIndex + y + x * back_TileRows]);
                        }
                    }
                }
            }
        }
        #endregion

        #region 元件框
        /// <summary>
        /// 聚焦框改变处理
        /// </summary>
        private void FocusRectChanged()
        {
            foreach (var item in ElementList)
            {
                item.IsSelected = false;
            }
            if (ControlList == null) ControlList = new ObservableCollection<ElementControl>();
            if (FocusRect == null) return;
            FocusRect.IsSelected = true;
            if (!ShowAllElement)
            { 
                ControlList.Clear();
                CreateElementControl(FocusRect);
            }
     
        }

        /// <summary>
        /// 框元素刷新处理
        /// </summary>
        private void ElementRefush()
        {
            if (!ShowAllElement) return;
            this.Dispatcher.Invoke(new Action(() =>
            {
                GetElementControlList();
                ElementList.CollectionChanged += ElementList_CollectionChanged;
                //ImageSizeChanged();
            }));
        }


        /// <summary>
        /// 框元素集合改变处理
        /// </summary>
        private void ElementList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            this.Dispatcher.Invoke(new Action(() =>
            {

                switch (e.Action)
                {
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                        foreach (ElementBaseModel item in e.NewItems)
                        {
                            CreateElementControl(item);
                        }
                        break;
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                        foreach (ElementBaseModel item in e.OldItems)
                        {
                            var control = ControlList.FirstOrDefault(t => t.Info.Key == item.Key);
                            if (control == null) continue;
                            ControlList.Remove(control);
                        }
                        break;
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                        GetElementControlList();
                        break;
                }
            }));
        }

        /// <summary>
        /// 框控件集合处理
        /// </summary>
        private void GetElementControlList()
        {
            ControlList = new ObservableCollection<ElementControl>();
            if (ElementList == null) return;
            foreach (var item in ElementList.Where(t => t.Shape != ShapeEnum.多边形))
            {
                CreateElementControl(item);
            }
        }

        /// <summary>
        /// 基于框元素生成框对象
        /// </summary>
        /// <param name="item">框元素</param>
        private void CreateElementControl(ElementBaseModel item)
        {
            ElementControl element = new ElementControl();
            ControlList.Add(element);
            element.Info = item;
            Binding bind = new Binding();
            bind.Source = this;
            bind.Path = new PropertyPath("ScaleX");
            bind.Mode = BindingMode.TwoWay;
            bind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            element.SetBinding(ElementControl.ScaleValueProperty, bind);
            Binding nameBind = new Binding();
            nameBind.Source = this;
            nameBind.Path = new PropertyPath("ElementNameVisit");
            nameBind.Mode = BindingMode.TwoWay;
            nameBind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            element.SetBinding(ElementControl.NameVisitProperty, nameBind);
        }


        /// <summary>
        /// 绘制框处理
        /// </summary>
        /// <param name="newPoint">当前鼠标位置</param>
        private void DrawRectByMove(Point newPoint)
        {
            if (ElementList == null) ElementList = new ObservableCollection<ElementBaseModel>();
            if (ElementList.FirstOrDefault(t => t.Key == drawingRect.Key) == null)
            {
                foreach (var item in ElementList)
                {
                    item.IsSelected = false;
                }
                ElementList.Add(drawingRect);
            }
            if (newPoint.X < lastMouseLeftDownPoint.X && newPoint.Y < lastMouseLeftDownPoint.Y)
            {
                drawingRect.X = (newPoint.X - calc_CanvasX) / calc_ScaleX;
                drawingRect.Y = (newPoint.Y - calc_CanvasY) / calc_ScaleY;
            }
            else if (newPoint.X >= lastMouseLeftDownPoint.X && newPoint.Y < lastMouseLeftDownPoint.Y)
            {
                drawingRect.X = (lastMouseLeftDownPoint.X - calc_CanvasX) / calc_ScaleX;
                drawingRect.Y = (newPoint.Y - calc_CanvasY) / calc_ScaleY;
            }
            else if (newPoint.X < lastMouseLeftDownPoint.X && newPoint.Y >= lastMouseLeftDownPoint.Y)
            {
                drawingRect.X = (newPoint.X - calc_CanvasX) / calc_ScaleX;
                drawingRect.Y = (lastMouseLeftDownPoint.Y - calc_CanvasY) / calc_ScaleY;
            }
            else
            {
                drawingRect.X = (lastMouseLeftDownPoint.X - calc_CanvasX) / calc_ScaleX;
                drawingRect.Y = (lastMouseLeftDownPoint.Y - calc_CanvasY) / calc_ScaleY;
            }
            drawingRect.Width = Math.Abs(newPoint.X - lastMouseLeftDownPoint.X) / calc_ScaleX;
            drawingRect.Height = Math.Abs(newPoint.Y - lastMouseLeftDownPoint.Y) / calc_ScaleY;
        }


        /// <summary>
        /// 鼠标点击点与多边形包含判断
        /// </summary>
        /// <param name="point"></param>
        /// <param name="polygon"></param>
        /// <returns></returns>
        private bool IsPointInPolygon(Point point, List<Point> polygon)
        {

            bool? sign = null;
            for (int i = 0; i < polygon.Count; i++)
            {
                var next = i == polygon.Count - 1 ? 0 : i + 1;

                var currentPoint = polygon[i];
                var nextPoint = polygon[next];
                var v = nextPoint - currentPoint;
                var p = point;
                var vp = p - currentPoint;
                var n = Vector.CrossProduct(v, vp);
                if (n > 0)
                {
                    if (sign == null) sign = true;
                    else if (sign == false) return false;
                }
                else if (n < 0)
                {
                    if (sign == null) sign = false;
                    else if (sign == true) return false;
                }
            }
            return true;
        }

        /// <summary>
        /// 鼠标点击点和元件框相机判断
        /// </summary>
        /// <param name="point"></param>
        /// <param name="element"></param>
        /// <returns></returns>
        private bool IntersectsWith(Point point, ElementBaseModel element)
        {
            switch (element.Shape)
            {
                case ShapeEnum.矩形:
                case ShapeEnum.圆形:
                    {
                        Rect src = new Rect((point.X - 1 - calc_CanvasX) / calc_ScaleX, (point.Y - 1 - calc_CanvasY) / calc_ScaleY, 2 / ScaleY, 2 / ScaleY);
                        Rect des = new Rect(element.X, element.Y, element.Width, element.Height);
                        return src.IntersectsWith(des);
                    }
                case ShapeEnum.多边形:
                    return IsPointInPolygon(new Point((point.X - calc_CanvasX) / calc_ScaleX, (point.Y - calc_CanvasY) / calc_ScaleY), element.Points.ToList());
                case ShapeEnum.线段:
                    {
                        Rect src = new Rect((point.X - 1 - calc_CanvasX) / calc_ScaleX, (point.Y - 1 - calc_CanvasY) / calc_ScaleY, 2 / calc_ScaleY, 2 / calc_ScaleY);
                        var allPoints = element.PathList.SelectMany(t => t.Points).ToList();
                        Rect des = new Rect(allPoints.Min(x => x.X), allPoints.Min(x => x.Y), allPoints.Max(x => x.X) - allPoints.Min(x => x.X), allPoints.Max(x => x.Y) - allPoints.Min(x => x.Y));
                        if (des.Width < 100)
                        {
                            des.X -= 50;
                            des.X = des.X < 0 ? 0 : des.X;
                            des.Width += 100;
                        }
                        if (des.Height < 100)
                        {
                            des.Y -= 50;
                            des.Y = des.Y < 0 ? 0 : des.Y;
                            des.Height += 100;
                        }
                        return src.IntersectsWith(des);
                    }
                default:
                    return false;
            }

        } 
        #endregion

        #region 控件事件
        /// <summary>
        /// 控件尺寸改变处理
        /// </summary>
        private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            ImageSizeChanged();
        }

        /// <summary>
        /// 画布鼠标左键按下处理
        /// </summary>
        private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            lastMouseLeftDownPoint = e.GetPosition(sender as Canvas);
            isLeftMouseDown = true;
            this.Focus();
            if (Keyboard.IsKeyDown(Key.LeftCtrl) || (Status == ImageStatusEnum.概览))
            {
                if (ElementList == null) return;
                var list = ElementList.Where(t => IntersectsWith(lastMouseLeftDownPoint, t)).ToList();
                if (list.Count == 0) return;
                if (!ShowAllElement)
                    ControlList = new ObservableCollection<ElementControl>();
                var temp = list.FirstOrDefault(t => t.IsSelected);
                ElementBaseModel tempElement = null;
                if (temp == null)
                {
                    foreach (var item in ElementList)
                    {
                        item.IsSelected = false;
                    }
                    tempElement = list.FirstOrDefault();
                }
                else
                {
                    int index = list.IndexOf(temp);
                    foreach (var item in ElementList)
                    {
                        item.IsSelected = false;
                    }
                    tempElement = list[(index + 1) % list.Count];
                }
                if (tempElement != null)
                {
                    tempElement.IsSelected = true;
                    if (!ShowAllElement)
                        CreateElementControl(tempElement);
                }
            }
            else if (Keyboard.IsKeyDown(Key.LeftAlt))
            {
            }
            else
            {
                switch (Status)
                {
                    case ImageStatusEnum.编辑:

                        switch (SelectedShape)
                        {
                            case ShapeEnum.矩形:
                            case ShapeEnum.圆形:
                                if (ElementList != null)
                                    foreach (var item in ElementList)
                                    {
                                        item.IsSelected = false;
                                    }
                                drawingRect = new ElementBaseModel() { BrushString = DrawingRectBrush.ToString(), Shape = SelectedShape, IsSelected = true };
                                drawingRect.X = (lastMouseLeftDownPoint.X - calc_CanvasX) / calc_ScaleX;
                                drawingRect.Y = (lastMouseLeftDownPoint.Y - calc_CanvasY) / calc_ScaleY;
                                break;
                            case ShapeEnum.多边形:
                                if (drawingRect == null || !ElementList.Contains(drawingRect))
                                {
                                    if (ElementList == null) ElementList = new ObservableCollection<ElementBaseModel>();
                                    drawingRect = new ElementBaseModel()
                                    {
                                        BrushString = DrawingRectBrush.ToString(),
                                        Shape = SelectedShape,
                                        IsSelected = true,
                                    };
                                    ElementList.Add(drawingRect);
                                    //CreateElementControl(drawingRect);
                                }
                                drawingRect.Points.Add(new Point((lastMouseLeftDownPoint.X - calc_CanvasX) / calc_ScaleX, (lastMouseLeftDownPoint.Y - calc_CanvasY) / calc_ScaleY));
                                break;
                        }
                        break;
                    case ImageStatusEnum.选点:
                        Position_X = (lastMouseLeftDownPoint.X - calc_CanvasX) / calc_ScaleX;
                        Position_Y = (lastMouseLeftDownPoint.Y - calc_CanvasY) / calc_ScaleY;
                        break;
                }
            }
        }

        /// <summary>
        /// Mapping画布鼠标左键按下处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Canvas_MouseLeftButtonDown_Mapping(object sender, MouseButtonEventArgs e)
        {
            if (!MappingEnabled) return;
            if (Rect_Mapping.Width > MappingWidth || Rect_Mapping.Height > MappingHeight)
            {
                MappingVisit = Visibility.Collapsed;
                return;
            }
            MappingVisit = Visibility.Visible;
            lastMouseLeftDownPoint_Mapping = e.GetPosition(sender as Canvas);
            Point point = Mouse.GetPosition(sender as Canvas);
            double dx = point.X - Rect_Mapping.Width / 2;
            double dy = point.Y - Rect_Mapping.Height / 2;
            double srcDx = -dx * ImageWidth / MappingWidth;
            double srcDy = -dy * ImageHeight / MappingHeight;
            Canvas.SetLeft(Rect_Mapping, dx);
            Canvas.SetTop(Rect_Mapping, dy);
            CanvasX = calc_CanvasX = (orgX + srcDx) * calc_ScaleX;
            CanvasY = calc_CanvasY = (orgY + srcDy) * calc_ScaleY;
            if (LoadModel == ImageLoadModelEnum.瓦片)
                TileRefush(new Point(showAreaActualWidth / 2, showAreaActualHeight / 2), (int)(ImageWidth * calc_ScaleX), true);
        }

        private void Canvas_MouseMove_Mapping(object sender, MouseEventArgs e)
        {
            if (e.LeftButton != MouseButtonState.Pressed || !MappingEnabled) return;
            if (Rect_Mapping.Width > MappingWidth || Rect_Mapping.Height > MappingHeight)
            {
                MappingVisit = Visibility.Collapsed;
                return;
            }
            MappingVisit = Visibility.Visible;
            Point point = Mouse.GetPosition(sender as Canvas);
            var px = point.X - lastMouseLeftDownPoint_Mapping.X;
            var py = point.Y - lastMouseLeftDownPoint_Mapping.Y;

                CanvasX = calc_CanvasX -= px * ImageWidth / MappingWidth;
                CanvasY = calc_CanvasY -= py * ImageHeight / MappingHeight;
            lastMouseLeftDownPoint_Mapping = point;
            Canvas.SetLeft(Rect_Mapping, Canvas.GetLeft(Rect_Mapping) + px);
            Canvas.SetTop(Rect_Mapping, Canvas.GetTop(Rect_Mapping) + py);
            if (LoadModel == ImageLoadModelEnum.瓦片)
                TileRefush(new Point(showAreaActualWidth / 2, showAreaActualHeight / 2), (int)(ImageWidth * calc_ScaleX), true);
        }

        /// <summary>
        /// 话布鼠标左键弹起处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {

            isLeftMouseDown = false;
            switch (SelectedShape)
            {
                case ShapeEnum.矩形:
                case ShapeEnum.圆形:
                    drawingRect = null;
                    break;
                case ShapeEnum.多边形:
                    break;
            }
        }


        /// <summary>
        /// 画布鼠标右键按下处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            switch (SelectedShape)
            {
                case ShapeEnum.矩形:
                case ShapeEnum.圆形:
                    break;
                case ShapeEnum.多边形:
                    if (drawingRect != null && drawingRect.Points != null && drawingRect.Points.Count > 0)
                    {
                        drawingRect.Points.Remove(drawingRect.Points.LastOrDefault());
                    }
                    break;
            }
        }

        /// <summary>
        /// 画布鼠标移动处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Canvas_MouseMove(object sender, MouseEventArgs e)
        {
            var newPoint = e.GetPosition(sender as Canvas);

            MouseX = (newPoint.X - calc_CanvasX) / calc_ScaleX;
            MouseY = (newPoint.Y - calc_CanvasY) / calc_ScaleY;

            switch (Status)
            {
                case ImageStatusEnum.浏览:
                    if (e.LeftButton != MouseButtonState.Pressed || !isLeftMouseDown) return;
                    var px = newPoint.X - lastMouseLeftDownPoint.X;
                    var py = newPoint.Y - lastMouseLeftDownPoint.Y;
                    if (MoveOverEnabled || ((-(calc_CanvasX + px - showAreaActualWidth) <= ImageWidth * calc_ScaleX) && (-(calc_CanvasX + px) >= 0)))
                    {
                        calc_CanvasX = CanvasX += px;
                    }
                    if (MoveOverEnabled || ((-(calc_CanvasY + py - showAreaActualHeight) <= ImageHeight * calc_ScaleY) && ((calc_CanvasY + py) <= 0)))
                    {
                        calc_CanvasY = CanvasY += py;
                    }
                    lastMouseLeftDownPoint = newPoint;
                    Canvas.SetLeft(Rect_Mapping, -calc_CanvasX / calc_ScaleX * MappingWidth / ImageWidth);
                    Canvas.SetTop(Rect_Mapping, -calc_CanvasY / calc_ScaleY * MappingHeight / ImageHeight);
                    if (LoadModel == ImageLoadModelEnum.瓦片)
                        TileRefush(new Point(showAreaActualWidth / 2, showAreaActualHeight / 2), (int)(ImageWidth * calc_ScaleX), true);
                    break;
                case ImageStatusEnum.编辑:
                    if (drawingRect == null || e.LeftButton != MouseButtonState.Pressed || !isLeftMouseDown || SelectedShape == ShapeEnum.多边形) return;
                    DrawRectByMove(newPoint);
                    break;
            }

        }

        /// <summary>
        /// 鼠标中键处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ChangedButton == MouseButton.Middle)
            {
                drawingRect = null;
            }
        }

        /// <summary>
        /// 画布鼠标滚轮处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Canvas_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (Status != ImageStatusEnum.浏览 || !MouseWheelEnabled) return;
            var mousePoint = e.GetPosition(sender as Canvas);
            ScaleHand(mousePoint, e.Delta);
        }

        
        #endregion

        public ImageShowControl()
        {
            InitializeComponent();
            Task.Run(() => TileTaskHand());
        }




    }
}
